package com.guldan.jaina.provider;

import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.LinkedBlockingQueue;

import com.guldan.core.constants.CommonConstant;
import com.guldan.core.enums.CitizenUpdateTypeEn;
import com.guldan.core.enums.UploadTypeEn;
import com.guldan.core.exception.BusinessException;
import com.guldan.core.redis.CacheService;
import com.guldan.jaina.dto.citizenbatchupdate.CitizenBatchUpdateDTO;
import com.guldan.jaina.dto.citizenbatchupdate.CitizenBatchUpdateSearchDTO;
import com.guldan.jaina.dto.citizenfail.CitizenFailDTO;
import com.guldan.jaina.dto.citizenfail.CitizenFailSearchDTO;
import com.guldan.jaina.dto.progress.BarDTO;
import com.guldan.jaina.manager.CitizenBatchUpdateManager;
import com.guldan.jaina.manager.CitizenFailManager;
import com.guldan.jaina.task.CitizenUpdateThread;
import com.guldan.jaina.task.CitizenUploadThread;
import com.guldan.jaina.task.DownCitizenThread;
import com.guldan.jaina.utils.CitizenInfoDomainConvertUtils;
import com.guldan.jaina.utils.UserUtils;
import com.guldan.mapper.db.entity.CitizenInfo;
import com.guldan.mapper.db.entity.CitizenInfoExample;
import com.guldan.mapper.db.mapper.CitizenInfoMapperExt;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.guldan.core.dubbo.client.ResponseDTO;
import com.guldan.core.search.Pagination;
import com.guldan.jaina.dto.citizeninfo.CitizenInfoDTO;
import com.guldan.jaina.dto.citizeninfo.CitizenInfoSearchDTO;
import com.guldan.jaina.dto.citizeninfo.CitizenUploadResultDTO;
import com.guldan.jaina.manager.CitizenInfoManager;

/**
 * Created by Silas.
 * Date: 2016/11/7
 * Time: 22:54
 */
@Component
public class CitizenInfoProviderImpl implements ICitizenInfoProvider {

    public Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private CacheService cacheService;

    @Autowired
    private CitizenInfoManager citizenInfoManager;

    @Autowired
    private CitizenFailManager citizenFailManager;

    @Autowired
    private CitizenBatchUpdateManager citizenBatchUpdateManager;

    @Autowired
    private CitizenInfoMapperExt citizenInfoMapperExt;

    @Override
    public ResponseDTO<CitizenInfoDTO> get(Integer citizenInfoId) {
        ResponseDTO<CitizenInfoDTO> response = new ResponseDTO<>();
        response.setData(citizenInfoManager.get(citizenInfoId));
        return response;
    }

    @Override
    public ResponseDTO<CitizenInfoDTO> save(CitizenInfoDTO dto) {
        ResponseDTO<CitizenInfoDTO> response = new ResponseDTO<>();
        try {
            response.setData(citizenInfoManager.save(dto, false));
        } catch (Exception ex) {
            response.setStatus(false);
            response.setException(ex);
        }
        return response;
    }


    @Override
    public ResponseDTO<Boolean> delete(Integer citizenInfoId) {
        ResponseDTO<Boolean> response = new ResponseDTO<>();
        response.setData(citizenInfoManager.delete(citizenInfoId));
        return response;
    }

    @Override
    public ResponseDTO<Pagination<CitizenInfoDTO>> list(CitizenInfoSearchDTO citizenInfoSearchDTO) {
        ResponseDTO<Pagination<CitizenInfoDTO>> response = new ResponseDTO<>();
        response.setData(citizenInfoManager.list(citizenInfoSearchDTO));
        return response;
    }

    @Override
    public ResponseDTO<List<CitizenInfoDTO>> getCitizenInfoList(CitizenInfoSearchDTO citizenInfoSearchDTO) {
        ResponseDTO<List<CitizenInfoDTO>> response = new ResponseDTO<>();
        response.setData(citizenInfoManager.getCitizenInfoList(citizenInfoSearchDTO));
        return response;
    }

    @Override
    public ResponseDTO<Boolean> uploadCitizen() {
        return null;
    }


    //获取上传批次id，和时间
    @Override
    public ResponseDTO<List<CitizenFailDTO>> uploadBatchList() {
        ResponseDTO<List<CitizenFailDTO>> response = new ResponseDTO<>();
        response.setData(citizenFailManager.uploadBatchList());
        return response;
    }

    //获取导入失败人员列表
    @Override
    public ResponseDTO<CitizenFailDTO> getFail(Integer id) {
        ResponseDTO<CitizenFailDTO> response = new ResponseDTO<>();
        response.setData(citizenFailManager.get(id));
        return response;
    }

    //获取导入失败人员列表
    @Override
    public ResponseDTO<Pagination<CitizenFailDTO>> failList(CitizenFailSearchDTO searchDTO) {
        ResponseDTO<Pagination<CitizenFailDTO>> response = new ResponseDTO<>();
        response.setData(citizenFailManager.list(searchDTO));
        return response;
    }

    @Override
    public ResponseDTO<String> failListForDownload(CitizenFailSearchDTO searchDTO) {
        ResponseDTO<String> response = new ResponseDTO<>();
        Pagination<CitizenFailDTO> data = citizenFailManager.list(searchDTO);

        String key = String.format(CommonConstant.KEY_CITIZEN_FAIL_DATA, searchDTO.getBatchId());
        try {
            cacheService.putCache(key, data, 60 * 1); //60秒
        } catch (Exception ex) {
            //log.error("put " + String.format(CommonConstant.KEY_FINANCE_CREATE_DATA, summaryId) + " to redis error, count=" + subList.size());
        }
        response.setData(key);
        return response;
    }

    //上传人员列表
    @Override
    public ResponseDTO<BarDTO> uploadCitizen(List<CitizenInfoDTO> list) {
        ResponseDTO<BarDTO> response = new ResponseDTO<>();

        BarDTO barDTO = new BarDTO();

        try {

            LinkedBlockingQueue<CitizenInfoDTO> queue = new LinkedBlockingQueue<>();
            if (list != null && list.size() > 0) {
                for (CitizenInfoDTO dto : list) {

                    try {
                        queue.put(dto);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                String batchId = String.valueOf(System.currentTimeMillis());
                String barId = String.format(CommonConstant.KEY_BAR_UPLOAD_CITIZEN_ID, batchId);
                barDTO = new BarDTO(barId, UploadTypeEn.citizen.getCode(), queue.size());

                int number = 0;
                while (number < CommonConstant.THREAD_NUMBER_UPLOAD_CITIZEN) {
                    if (queue.size() < CommonConstant.THREAD_MAX_RECORD_COUNT) {
                        number = CommonConstant.THREAD_NUMBER_UPLOAD_CITIZEN;
                    }
                    number++;
                    String threadName = "CitizenUploadThread-" + batchId + "-" + number;

                    CitizenUploadThread citizenUploadThread = new CitizenUploadThread();
                    citizenUploadThread.setCitizenInfoManager(citizenInfoManager);
                    citizenUploadThread.setBatchId(batchId);
                    citizenUploadThread.setQueue(queue);
                    citizenUploadThread.setBarDTO(barDTO);
                    citizenUploadThread.setThreadName(threadName);
                    citizenUploadThread.setUsersDTO(UserUtils.getUser());
                    citizenUploadThread.setCacheService(cacheService);

                    Thread thread = new Thread(citizenUploadThread, threadName);
                    thread.start();
                }
            }

            response.setData(barDTO);

        } catch (Exception ex) {
            response.setStatus(false);
            response.setException(ex);
        }
        return response;
    }

    //批量更新银行卡，上传更新卡号模版
    @Override
    public ResponseDTO<BarDTO> uploadBank(List<CitizenBatchUpdateDTO> list) {
        int index = 1;
        List<CitizenBatchUpdateDTO> templateDataDTOList = new ArrayList<>();

        String batchId = Long.valueOf(System.currentTimeMillis()).toString();

        String barId = String.format(CommonConstant.KEY_BAR_UPLOAD_CITIZEN_UPDATE_ID, batchId);
        BarDTO barDTO = new BarDTO(barId, UploadTypeEn.citizen_update.getCode(), list.size());

        for (int i = 0; i < list.size(); i++) {

            CitizenBatchUpdateDTO temp = list.get(i);
            temp.setBatchId(batchId);
            temp.setCreatorAreaId(UserUtils.getUser().getAreaId());
            templateDataDTOList.add(temp);

            if (index % 100 == 0 || index == list.size()) {
                //每100个数一个线程，来执行；或者循环到列表结尾，将剩下的数量交给最后一个线程来执行
                CitizenUpdateThread citizenUpdateThread = new CitizenUpdateThread();

                String threadName = "CitizenUpdateThread-" + System.currentTimeMillis();

                citizenUpdateThread.setThreadName(threadName);
                citizenUpdateThread.setData(list);
                citizenUpdateThread.setUpdateType(CitizenUpdateTypeEn.citizen_bank.getCode());
                citizenUpdateThread.setCitizenBatchUpdateManager(citizenBatchUpdateManager);
                citizenUpdateThread.setBarDTO(barDTO);
                citizenUpdateThread.setUsersDTO(UserUtils.getUser());

                Thread thread = new Thread(citizenUpdateThread, threadName);
                thread.start();

                logger.info(threadName + " started, size " + templateDataDTOList.size());

                try {
                    Thread.sleep(50L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                templateDataDTOList = new ArrayList<>();
            }
            index++;
        }

        ResponseDTO<BarDTO> responseDTO = new ResponseDTO<>();
        responseDTO.setData(barDTO);
        return responseDTO;
    }

    //批量更新银行卡，上传批次列表
    @Override
    public ResponseDTO<List<CitizenBatchUpdateDTO>> uploadBatchList(CitizenBatchUpdateSearchDTO dto) {
        ResponseDTO<List<CitizenBatchUpdateDTO>> response = new ResponseDTO<>();
        response.setData(citizenBatchUpdateManager.uploadBatchList(dto));
        return response;
    }

    //批量更新银行卡，查看失败记录列表
    @Override
    public ResponseDTO<Pagination<CitizenBatchUpdateDTO>> uploadFailList(CitizenBatchUpdateSearchDTO searchDTO) {
        ResponseDTO<Pagination<CitizenBatchUpdateDTO>> response = new ResponseDTO<>();
        response.setData(citizenBatchUpdateManager.list(searchDTO));
        return response;
    }

    //批量更新银行卡，下载批失败列表
    @Override
    public ResponseDTO<List<CitizenBatchUpdateDTO>> downFailList(CitizenBatchUpdateSearchDTO searchDTO) {
        ResponseDTO<List<CitizenBatchUpdateDTO>> response = new ResponseDTO<>();
        searchDTO.setPerPage(100000000);
        response.setData(citizenBatchUpdateManager.list(searchDTO).getList());
        return response;
    }

    //批量更新姓名，上传更新姓名模版
    @Override
    public ResponseDTO<BarDTO> uploadName(List<CitizenBatchUpdateDTO> list) {
        int index = 1;
        List<CitizenBatchUpdateDTO> templateDataDTOList = new ArrayList<>();

        String batchId = Long.valueOf(System.currentTimeMillis()).toString();

        String barId = String.format(CommonConstant.KEY_BAR_UPLOAD_CITIZEN_UPDATE_ID, batchId);
        BarDTO barDTO = new BarDTO(barId, UploadTypeEn.citizen_update.getCode(), list.size());


        for (int i = 0; i < list.size(); i++) {

            CitizenBatchUpdateDTO temp = list.get(i);
            temp.setBatchId(batchId);
            temp.setCreatorAreaId(UserUtils.getUser().getAreaId());
            templateDataDTOList.add(temp);

            if (index % 100 == 0 || index == list.size()) {
                //每100个数一个线程，来执行；或者循环到列表结尾，将剩下的数量交给最后一个线程来执行
                CitizenUpdateThread citizenUpdateThread = new CitizenUpdateThread();

                String threadName = "CitizenUpdateThread-" + System.currentTimeMillis();

                citizenUpdateThread.setThreadName(threadName);
                citizenUpdateThread.setData(list);
                citizenUpdateThread.setUpdateType(CitizenUpdateTypeEn.citizen_name.getCode());
                citizenUpdateThread.setCitizenBatchUpdateManager(citizenBatchUpdateManager);
                citizenUpdateThread.setBarDTO(barDTO);
                citizenUpdateThread.setUsersDTO(UserUtils.getUser());

                Thread thread = new Thread(citizenUpdateThread, threadName);
                thread.start();

                logger.info(threadName + " started, size " + templateDataDTOList.size());

                try {
                    Thread.sleep(50L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                templateDataDTOList = new ArrayList<>();
            }
            index++;
        }

        ResponseDTO<BarDTO> responseDTO = new ResponseDTO<>();
        responseDTO.setData(barDTO);
        return responseDTO;
    }

    //批量更新区划。上传更新区划模版
    @Override
    public ResponseDTO<BarDTO> uploadArea(List<CitizenBatchUpdateDTO> list) {
        int index = 1;
        List<CitizenBatchUpdateDTO> templateDataDTOList = new ArrayList<>();

        String batchId = Long.valueOf(System.currentTimeMillis()).toString();

        String barId = String.format(CommonConstant.KEY_BAR_UPLOAD_CITIZEN_UPDATE_ID, batchId);
        BarDTO barDTO = new BarDTO(barId, UploadTypeEn.citizen_update.getCode(), list.size());


        for (int i = 0; i < list.size(); i++) {

            CitizenBatchUpdateDTO temp = list.get(i);
            temp.setBatchId(batchId);
            temp.setCreatorAreaId(UserUtils.getUser().getAreaId());
            templateDataDTOList.add(temp);

            if (index % 100 == 0 || index == list.size()) {
                //每100个数一个线程，来执行；或者循环到列表结尾，将剩下的数量交给最后一个线程来执行
                CitizenUpdateThread citizenUpdateThread = new CitizenUpdateThread();

                String threadName = "CitizenUpdateThread-" + System.currentTimeMillis();

                citizenUpdateThread.setThreadName(threadName);
                citizenUpdateThread.setData(list);
                citizenUpdateThread.setUpdateType(CitizenUpdateTypeEn.citizen_area.getCode());
                citizenUpdateThread.setCitizenBatchUpdateManager(citizenBatchUpdateManager);
                citizenUpdateThread.setBarDTO(barDTO);
                citizenUpdateThread.setUsersDTO(UserUtils.getUser());

                Thread thread = new Thread(citizenUpdateThread, threadName);
                thread.start();

                logger.info(threadName + " started, size " + templateDataDTOList.size());

                try {
                    Thread.sleep(50L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                templateDataDTOList = new ArrayList<>();
            }
            index++;
        }

        ResponseDTO<BarDTO> responseDTO = new ResponseDTO<>();
        responseDTO.setData(barDTO);
        return responseDTO;
    }


    //导出人员信息记录
    @Override
    public ResponseDTO<String> downCitizenList(CitizenInfoSearchDTO citizenInfoSearchDTO) throws BusinessException {

        if (citizenInfoSearchDTO.getAreaId() == null) {
            citizenInfoSearchDTO.setAreaId(UserUtils.getUser().getAreaId());
        }

        ResponseDTO<String> response = new ResponseDTO<>();

        CitizenInfoExample example = citizenInfoManager.buildSearchExample(citizenInfoSearchDTO);
        int total = citizenInfoMapperExt.countByExample(example);

        if (total > 80000) {
            response.setStatus(false);
            response.setException(new BusinessException("导出记录数超过最大限制80000"));
            return response;
        }

        Vector<Thread> threads = new Vector<Thread>();
        LinkedBlockingQueue<CitizenInfoDTO> data = new LinkedBlockingQueue<CitizenInfoDTO>();
        LinkedBlockingQueue<CitizenInfoDTO> queue = new LinkedBlockingQueue<>();
        if (total > 0) {
            List<CitizenInfo> list = citizenInfoMapperExt.selectByExample(example);
            for (CitizenInfo entity : list) {
                CitizenInfoDTO dto = CitizenInfoDomainConvertUtils.convert(entity);
                try {
                    queue.put(dto);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

/*
            class DownCitizenThread implements Runnable {

                @Override
                public void run() {
                    try {
                        while (!queue.isEmpty()) {
                            CitizenInfoDTO d = queue.take();
                            d = getCitizenDTOForDown(d);
                            data.put(d);
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        logger.info("DownCitizenThread-finish queue.size():" + queue.size());
                    }
                }
            }*/

            String t = Long.valueOf(System.currentTimeMillis()).toString();

            int number = 0;
            while (number < CommonConstant.THREAD_NUMBER_UPLOAD_CITIZEN) {
                if (queue.size() < CommonConstant.THREAD_MAX_RECORD_COUNT) {
                    number = CommonConstant.THREAD_NUMBER_UPLOAD_CITIZEN;
                }
                number++;
                String threadName = "DownCitizenThread-" + t + "-" + number;

                DownCitizenThread downCitizenThread = new DownCitizenThread();
                downCitizenThread.setQueue(queue);
                downCitizenThread.setData(data);
                downCitizenThread.setCitizenInfoManager(citizenInfoManager);
                downCitizenThread.setThreadName(threadName);

                Thread thread = new Thread(downCitizenThread, threadName);
                threads.add(thread);
                thread.start();
            }

            for (Thread iThread : threads) {
                try {
                    //等待所有线程执行完毕
                    iThread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        //
        logger.info("子线程均执行完毕");

        List<CitizenInfoDTO> result = new ArrayList<>();

        /*while (data.size() < total) {

            logger.info("sleep 1s");
            *//*try {
                Thread.sleep(1000L);
                logger.info("sleep 1s");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }*//*
        }*/
        while (!data.isEmpty()) {
            try {
                result.add(data.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        queue.clear();
        data.clear();


        String key = String.format(CommonConstant.KEY_CITIZEN_DOWN_DATA, System.currentTimeMillis());
        try {
            cacheService.putCache(key, result, 60 * 1); //60秒
        } catch (Exception ex) {
            //log.error("put " + String.format(CommonConstant.KEY_FINANCE_CREATE_DATA, summaryId) + " to redis error, count=" + subList.size());
        }
        response.setData(key);

//        response.setData(result);

        logger.info("downCitizenList ori.size:" + total + " down.size:" + result.size());

        return response;
    }

}
